home *** CD-ROM | disk | FTP | other *** search
- /*
- * fsStreamOps.c --
- *
- * The has procedures for the following stream operations:
- * Read, Write, IOControl, Close. Select and attributes functions
- * are in their own files.
- *
- * Copyright 1987 Regents of the University of California
- * All rights reserved.
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fs/fsStreamOps.c,v 9.34 92/09/22 16:14:29 jhh Exp $ SPRITE (Berkeley)";
- #endif not lint
-
-
- #include <sprite.h>
- #include <fs.h>
- #include <fsutil.h>
- #include <fsio.h>
- #include <fsNameOps.h>
- #include <fscache.h>
- #include <fsStat.h>
- #include <fsdm.h>
- #include <fsprefix.h>
- #include <rpc.h>
- #include <vm.h>
- #include <fsrmt.h>
- #include <fslcl.h>
- #include <assert.h>
- #include <machparam.h>
- #include <string.h>
- #include <fspdev.h>
- #include <recov.h>
-
- extern Boolean fsconsist_ClientCachingEnabled;
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_Read --
- *
- * Read from a stream. The main jobs of this routine are to
- * set things up for (remote) waiting, and to branch out to
- * the procedure that implements Read for the type of the stream.
- * If the server is down, or the stream's handle has gone stale,
- * this blocks the process while waiting for handle recovery.
- * Also, the stream access position is maintained by this procedure,
- * even though the read offset is an explicit argument.
- *
- * Results:
- * A return status, SUCCESS if successful.
- *
- * Side effects:
- * The buffer is filled with the number of bytes indicated by
- * the length parameter. The in/out length parameter specifies
- * the buffer size on input and is updated to reflect the number
- * of bytes actually read.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fs_Read(streamPtr, buffer, offset, lenPtr)
- Fs_Stream *streamPtr; /* Stream to read from. */
- Address buffer; /* Where to read into. */
- int offset; /* Where to start reading from. */
- int *lenPtr; /* Contains number of bytes to read on input,
- and is filled with number of bytes read. */
- {
- register ReturnStatus status = SUCCESS;
- Sync_RemoteWaiter remoteWaiter;
- Fs_IOParam io;
- register Fs_IOParam *ioPtr = &io;
- Fs_IOReply reply;
- int streamType;
- register int toRead;
- int amtRead;
-
- toRead = *lenPtr;
- *lenPtr = 0;
- amtRead = 0;
- if (sys_ShuttingDown) {
- return(FAILURE);
- } else if ((streamPtr->flags & FS_READ) == 0) {
- return(FS_NO_ACCESS);
- } else if (toRead == 0) {
- return(SUCCESS);
- } else if ((toRead < 0) || (offset < 0)) {
- return(GEN_INVALID_ARG);
- } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
- return(FS_STALE_HANDLE);
- }
- streamType = streamPtr->ioHandlePtr->fileID.type;
-
- FsSetIOParam(ioPtr, buffer, toRead, offset, streamPtr->flags);
- reply.length = 0;
- reply.flags = 0;
- reply.signal = 0;
- reply.code = 0;
-
- /*
- * Outer loop to attempt the read and then block if no data is ready.
- * The loop terminates upon error or if any data is transferred.
- */
- remoteWaiter.hostID = rpc_SpriteID;
- while (TRUE) {
- Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
-
- status = (fsio_StreamOpTable[streamType].read) (streamPtr,
- ioPtr, &remoteWaiter, &reply);
- #ifdef lint
- status = Fsio_FileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FsrmtFileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsio_DeviceRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsio_PipeRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FspdevControlRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FspdevServerStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FspdevPseudoStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsrmt_Read(streamPtr, ioPtr, &remoteWaiter, &reply);
- #endif
- if (status == SUCCESS) {
- if (streamType == FSIO_RMT_DEVICE_STREAM ||
- streamType == FSIO_RMT_PIPE_STREAM ||
- streamType == FSIO_RMT_PSEUDO_STREAM ||
- streamType == FSIO_RMT_PFS_STREAM ||
- streamType == FSIO_RMT_CONTROL_STREAM) {
- fs_Stats.rmtIO.remoteDevicishBytesRead += reply.length;
- }
- break;
- } else if (status == FS_WOULD_BLOCK &&
- (streamPtr->flags & FS_NON_BLOCKING) == 0) {
- /*
- * File streams will return FS_WOULD_BLOCK when waiting for a
- * cache block, but stuff has already been returned. We want
- * to wait instead of returning.
- */
- if ((reply.length > 0) && (streamType != FSIO_LCL_FILE_STREAM) &&
- (streamType != FSIO_RMT_FILE_STREAM)) {
- /*
- * Stream routine ought not do return FS_WOULD_BLOCK
- * in this case, but we cover for it here.
- */
- status = SUCCESS;
- break;
- } else {
- if (reply.length > 0) {
- /*
- * A cache block is unavailable, but data has already
- * been returned. Update the read request to start
- * with the unavailable block.
- */
- toRead -= reply.length;
- FsSetIOParam(ioPtr, io.buffer + reply.length,
- toRead, io.offset + reply.length, streamPtr->flags);
- }
- if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
- status = GEN_ABORTED_BY_SIGNAL;
- break;
- }
- }
- } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
- status == RPC_SERVICE_DISABLED) {
- status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
- if (status != SUCCESS) {
- break;
- }
- } else {
- if (status == FS_WOULD_BLOCK && reply.length > 0) {
- /*
- * Cannot return FS_WOULD_BLOCK if some data was read.
- */
- status = SUCCESS;
- }
- break;
- }
- /*
- * Restore the length parameter because it may have been set to
- * zero when the read blocked.
- */
- ioPtr->length = toRead;
- amtRead += reply.length;
- }
-
- amtRead += reply.length;
- /*
- * Cache the file offset for sequential access.
- */
- streamPtr->offset += amtRead;
- *lenPtr = amtRead;
-
- if (status == FS_BROKEN_PIPE) {
- Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
- } else if (reply.signal != 0) {
- Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
- }
- return(status);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_Write --
- *
- * Write to a stream. This sets up for (remote) waiting and then
- * branches to the routine that implements writing for the stream.
- * If the server is down, or the streams handle has gone stale,
- * this will block the process while waiting for handle recovery.
- * Finally, the stream access position of the stream is maintained
- * even though the write offset is an explicit parameter.
- *
- * Results:
- * A return status, SUCCESS if successful.
- *
- * Side effects:
- * The data in the buffer is written to the file at the indicated offset.
- * The in/out length parameter specifies the amount of data to write
- * and is updated to reflect the number of bytes actually written.
- * The stream offset field is updated to after the bytes written.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fs_Write(streamPtr, buffer, offset, lenPtr)
- Fs_Stream *streamPtr; /* The stream to write to */
- Address buffer; /* The buffer to fill in */
- int offset; /* Where in the stream to write to */
- int *lenPtr; /* In/Out byte count */
- {
- register ReturnStatus status = SUCCESS; /* I/O return status */
- Sync_RemoteWaiter remoteWaiter; /* Process info for waiting */
- Fs_IOParam io; /* Write parameter block */
- register Fs_IOParam *ioPtr = &io;
- Fs_IOReply reply; /* Return length, signal */
- int toWrite; /* Amount remaining to write.
- * Keep our own copy because
- * lower-levels may modify
- * ioPtr->length */
- register int amountWritten; /* Amount transferred */
- int streamType; /* Type from I/O handle */
-
- toWrite = *lenPtr;
- amountWritten = 0;
- *lenPtr = 0;
- if (sys_ShuttingDown) {
- return(FAILURE);
- } else if ((streamPtr->flags & FS_WRITE) == 0) {
- return(FS_NO_ACCESS);
- } else if (toWrite == 0) {
- return(SUCCESS);
- } else if ((toWrite < 0) || (offset < 0)) {
- return(GEN_INVALID_ARG);
- } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
- return(FS_STALE_HANDLE);
- }
- streamType = streamPtr->ioHandlePtr->fileID.type;
-
- FsSetIOParam(ioPtr, buffer, toWrite, offset, streamPtr->flags);
- reply.length = 0;
- reply.flags = 0;
- reply.signal = 0;
- reply.code = 0;
-
- remoteWaiter.hostID = rpc_SpriteID;
-
- /*
- * Main write loop. This handles partial writes, non-blocking streams,
- * and crash recovery. This loop expects the stream write procedure to
- * return FS_WOULD_BLOCK if it transfers no data, and lets it return
- * either SUCCESS or FS_WOULD_BLOCK on partial writes. SUCCESS with a
- * partial write makes this loop return.
- * If a stream write procedure returns FS_WOULD_BLOCK is is required to
- * have put the remoteWaiter information on an appropriate wait list.
- * This loop ensures that a non-blocking stream returns SUCCESS if some
- * data is transferred, and FS_WOULD_BLOCK if none can be transferred now.
- */
- while (TRUE) {
- Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
-
- status = (fsio_StreamOpTable[streamType].write) (streamPtr, ioPtr,
- &remoteWaiter, &reply);
- #ifdef lint
- status = Fsio_FileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FsrmtFileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsio_DeviceWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsio_PipeWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = FspdevPseudoStreamWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
- status = Fsrmt_Write(streamPtr, ioPtr, &remoteWaiter, &reply);
- #endif
- toWrite -= reply.length;
- amountWritten += reply.length;
- /*
- * Reset pointers because stream-specific routine may have
- * modified them arbitrarily.
- */
- ioPtr->buffer = buffer + amountWritten;
- ioPtr->offset = offset + amountWritten;
- ioPtr->length = toWrite;
- if (status == SUCCESS) {
- if (streamType == FSIO_RMT_DEVICE_STREAM ||
- streamType == FSIO_RMT_PIPE_STREAM ||
- streamType == FSIO_RMT_PSEUDO_STREAM ||
- streamType == FSIO_RMT_PFS_STREAM ||
- streamType == FSIO_RMT_CONTROL_STREAM) {
- fs_Stats.rmtIO.remoteDevicishBytesWritten += reply.length;
- }
- break;
- } else if (status == FS_WOULD_BLOCK) {
- if ((streamPtr->flags & FS_NON_BLOCKING) == 0) {
- if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
- status = GEN_ABORTED_BY_SIGNAL;
- break;
- }
- } else {
- if (amountWritten > 0) {
- status = SUCCESS; /* non-blocking partial write */
- }
- break;
- }
- } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
- status == RPC_SERVICE_DISABLED) {
- status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
- if (status != SUCCESS) {
- break;
- }
- } else {
- break; /* stream error */
- }
- }
- /*
- * Return info about the transfer.
- */
- *lenPtr = amountWritten;
- streamPtr->offset += amountWritten;
- if (status == FS_BROKEN_PIPE) {
- Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
- } else if (reply.signal != 0) {
- Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
- }
-
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_IOControl --
- *
- * Generic IOControl handler. This will also propogate ALL
- * IOControls down to lower levels, mainly so that pseudo-device
- * drivers (user-level server programs) will see all of them.
- *
- * Results:
- * An error code that depends in the command
- *
- * Side effects:
- * Command specific
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Fs_IOControl(streamPtr, ioctlPtr, replyPtr)
- register Fs_Stream *streamPtr;
- Fs_IOCParam *ioctlPtr; /* I/O Control parameter block */
- Fs_IOReply *replyPtr; /* Return length and signal */
- {
- register ReturnStatus status;
- register Boolean retry;
- register int command = ioctlPtr->command;
- int offset;
- Ioc_LockArgs *lockArgsPtr;
- register int streamType;
-
- lockArgsPtr = (Ioc_LockArgs *) NIL;
- /*
- * Retry loop to handle server error recovery and blocking locks.
- */
- streamType = streamPtr->ioHandlePtr->fileID.type;
- do {
- if (!Fsutil_HandleValid((Fs_HandleHeader *)streamPtr) ||
- !Fsutil_HandleValid((Fs_HandleHeader *)streamPtr->ioHandlePtr)) {
- return(FS_STALE_HANDLE);
- }
- retry = FALSE;
- replyPtr->length = ioctlPtr->outBufSize;
- replyPtr->flags = 0;
- replyPtr->signal = 0;
- replyPtr->code = 0;
- /*
- * Pre-processing for some of the IOControls.
- *
- * IOC_NUM_READABLE. We pass the stream offset
- * down using the inBuffer so that the stream-type-specific routines
- * can correctly compute how much data is available. (Still have to
- * do this even though we pass the streamPtr down because the offset
- * on the server may not be up-to-date. Probably fixable.)
- *
- * IOC_LOCK and IOC_UNLOCK. We have to fill in the process and hostID
- * entries in the buffer passed in from the user.
- *
- * IOC_PREFIX. This is processed here and not passed down to
- * lower levels. This looks at the streamPtr->nameInfoPtr which
- * is completely generic and not otherwise needed by lower levels.
- * This simplifies the object modules and eliminates an RPC in the
- * case that the object is remote.
- */
- if (command == IOC_NUM_READABLE) {
- offset = streamPtr->offset;
- ioctlPtr->inBuffer = (Address) &offset;
- ioctlPtr->inBufSize = sizeof(int);
- ioctlPtr->flags &= ~FS_USER_IN;
- } else if (command == IOC_LOCK || command == IOC_UNLOCK) {
- lockArgsPtr = (Ioc_LockArgs *)ioctlPtr->inBuffer;
- lockArgsPtr->hostID = rpc_SpriteID;
- Sync_GetWaitToken(&lockArgsPtr->pid, &lockArgsPtr->token);
- } else if (command == IOC_PREFIX) {
- Fsprefix *prefixPtr;
- if ((streamPtr->nameInfoPtr == (Fs_NameInfo *) NIL) ||
- (streamPtr->nameInfoPtr->prefixPtr == (Fsprefix *)NIL)) {
- status = GEN_INVALID_ARG;
- } else {
- prefixPtr = streamPtr->nameInfoPtr->prefixPtr;
- if (ioctlPtr->outBufSize < prefixPtr->prefixLength) {
- status = GEN_INVALID_ARG;
- } else {
- (void) strcpy(ioctlPtr->outBuffer, prefixPtr->prefix);
- replyPtr->length = prefixPtr->prefixLength + 1;
- status = SUCCESS;
- }
- }
- return(status); /* Do not pass down IOC_PREFIX */
- }
-
- status = (*fsio_StreamOpTable[streamType].ioControl)
- (streamPtr, ioctlPtr, replyPtr);
- #ifdef lint
- status = Fsio_FileIOControl(streamPtr, ioctlPtr, replyPtr);
- status = FsrmtFileIOControl(streamPtr, ioctlPtr, replyPtr);
- status = Fsio_DeviceIOControl(streamPtr, ioctlPtr, replyPtr);
- status = Fsrmt_IOControl(streamPtr, ioctlPtr, replyPtr);
- status = Fsio_PipeIOControl(streamPtr, ioctlPtr, replyPtr);
- status = FspdevControlIOControl(streamPtr, ioctlPtr, replyPtr);
- status = FspdevServerStreamIOControl(streamPtr, ioctlPtr, replyPtr);
- status = FspdevPseudoStreamIOControl(streamPtr, ioctlPtr, replyPtr);
- #endif /* lint */
-
- switch(status) {
- case SUCCESS:
- break;
- case RPC_TIMEOUT:
- case RPC_SERVICE_DISABLED:
- case FS_STALE_HANDLE:
- status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
- if (status == SUCCESS) {
- retry = TRUE;
- break;
- } else {
- return(status);
- }
- case FS_WOULD_BLOCK:
- /*
- * Blocking I/O control. Should be a lock, although some
- * pseudo-device servers (like ipServer) will return
- * this status code for their own reasons.
- */
- if ((command == IOC_LOCK) &&
- ((lockArgsPtr->flags & IOC_LOCK_NO_BLOCK) == 0)) {
- if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
- return(GEN_ABORTED_BY_SIGNAL);
- } else {
- retry = TRUE;
- break;
- }
- } else {
- return(status);
- }
- default:
- return(status);
- }
- } while (retry);
-
- /*
- * Do generic I/O controls that affect streams -
- * flag manipulation, and offset seeking.
- */
- switch (command) {
- case IOC_REPOSITION: {
- /*
- * Set the read/write offset of the stream.
- */
- register int newOffset;
- register Ioc_RepositionArgs *iocArgsPtr;
-
- if (ioctlPtr->inBuffer == (Address)NIL) {
- status = GEN_INVALID_ARG;
- break;
- }
- iocArgsPtr = (Ioc_RepositionArgs *)ioctlPtr->inBuffer;
- newOffset = -1;
- switch(iocArgsPtr->base) {
- case IOC_BASE_ZERO:
- newOffset = iocArgsPtr->offset;
- break;
- case IOC_BASE_CURRENT:
- newOffset = streamPtr->offset + iocArgsPtr->offset;
- break;
- case IOC_BASE_EOF: {
- Fs_Attributes attrs;
-
- status = Fs_GetAttrStream(streamPtr, &attrs);
- if (status != SUCCESS) {
- break;
- }
- newOffset = attrs.size + iocArgsPtr->offset;
- break;
- }
- }
- if (newOffset < 0) {
- status = GEN_INVALID_ARG;
- } else {
- if (ioctlPtr->outBuffer != (Address)NIL) {
- *(int *)ioctlPtr->outBuffer = newOffset;
- replyPtr->length = sizeof(int);
- }
- streamPtr->offset = newOffset;
- }
- break;
- }
- /*
- * Stream flags manipulation. There are the FS_ constants which
- * have a place in the streams flag field, and the IOC_ constants
- * which user programs know about. These allow flexibility, but
- * requires specific checking for each kernel flag...
- */
- case IOC_GET_FLAGS: {
- /*
- * OR the kernel flags from the stream into the output flags word.
- */
- register int flags = 0;
- if (streamPtr->flags & FS_APPEND) {
- flags |= IOC_APPEND;
- }
- if (streamPtr->flags & FS_NON_BLOCKING) {
- flags |= IOC_NON_BLOCKING;
- }
- if (streamPtr->flags & FS_READ) {
- flags |= IOC_READ;
- }
- if (streamPtr->flags & FS_WRITE) {
- flags |= IOC_WRITE;
- }
- if (ioctlPtr->outBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- } else {
- *(int *)ioctlPtr->outBuffer |= flags;
- replyPtr->length = sizeof(int);
- }
- break;
- }
- case IOC_SET_BITS:
- case IOC_SET_FLAGS: {
- /*
- * Set any kernel stream flags specifid by the IOControl flags.
- * We rely on the file-type IOControl routine to verify
- * the validity of the flag choices. See that IOC_SET_FLAGS
- * differs from IOC_SET_BITS by turning off any bits that
- * are not in the input word.
- */
- register int flags;
- if (ioctlPtr->inBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- break;
- }
- flags = *(int *)ioctlPtr->inBuffer;
- if ((flags & IOC_APPEND) && (streamPtr->flags & FS_WRITE) == 0) {
- status = FS_NO_ACCESS;
- break;
- }
- if (flags & IOC_APPEND) {
- streamPtr->flags |= FS_APPEND;
- } else if (command == IOC_SET_FLAGS) {
- streamPtr->flags &= ~FS_APPEND;
- }
- if (flags & IOC_NON_BLOCKING) {
- streamPtr->flags |= FS_NON_BLOCKING;
- } else if (command == IOC_SET_FLAGS) {
- streamPtr->flags &= ~FS_NON_BLOCKING;
- }
- break;
- }
- case IOC_CLEAR_BITS:{
- register int flags;
- if (ioctlPtr->inBufSize != sizeof(int)) {
- status = GEN_INVALID_ARG;
- break;
- }
- flags = *(int *)ioctlPtr->inBuffer;
- if (flags & IOC_APPEND) {
- streamPtr->flags &= ~FS_APPEND;
- }
- if (flags & IOC_NON_BLOCKING) {
- streamPtr->flags &= ~FS_NON_BLOCKING;
- }
- break;
- }
- /*
- * Everything for the following has already been handled by
- * the stream specific IOControl routines.
- */
- case IOC_LOCK:
- case IOC_UNLOCK:
- case IOC_NUM_READABLE:
- case IOC_TRUNCATE:
- case IOC_GET_OWNER:
- case IOC_SET_OWNER:
- case IOC_MAP:
- break;
- }
- /*
- * Generate signal returned from stream-specific routine.
- */
- if (replyPtr->signal != 0) {
- Sig_Send(replyPtr->signal, replyPtr->code, PROC_MY_PID, FALSE,
- (Address)0);
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_Close --
- *
- * Free this reference to the Stream. The reference count is decreased
- * and when it goes to zero the stream close routine is called
- * to release the reference to the I/O handle.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If the ref count is zero after the decrement, the reference to
- * the file is released and the input parameter is free'd.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Fs_Close(streamPtr)
- register Fs_Stream *streamPtr;
- {
- register ReturnStatus status;
- Proc_ControlBlock *procPtr;
- Boolean retry;
-
- if (streamPtr == (Fs_Stream *)NIL) {
- /*
- * Bomb-proofing. The current directory sometimes doesn't get
- * found at boot time and so there is a NIL streamPtr around for it.
- */
- return(FS_INVALID_ARG);
- }
- Fsutil_HandleLock(streamPtr);
- procPtr = Proc_GetEffectiveProc();
- if (streamPtr->hdr.refCount > 1) {
- /*
- * There are other copies of the stream (due to fork/dup) so
- * we don't close the I/O handle yet.
- */
- Fsutil_HandleRelease(streamPtr, TRUE);
- return SUCCESS;
- }
- /*
- * Call the stream type close routine to clean up this reference
- * to the I/O handle.
- */
- Fsutil_HandleLock(streamPtr->ioHandlePtr);
-
- do {
- retry = FALSE;
- status = (fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].close)
- (streamPtr, rpc_SpriteID, procPtr->processID, streamPtr->flags,
- 0, (ClientData)NIL);
- #ifdef lint
- status = Fsio_FileClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = FsrmtFileClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = Fsio_PipeClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = Fsio_DeviceClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = Fsrmt_IOClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = FspdevControlClose(streamPtr, rpc_SpriteID, procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = FspdevPseudoStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- status = FspdevServerStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
- streamPtr->flags, 0, (ClientData)NIL);
- #endif /* lint */
- /*
- * If the server will recover quickly, then it should be okay
- * to hang here. We didn't use to. This is only worth doing in
- * transparent server recovery, where it depends on correct
- * reference counts. Therefore recov_Transparent must be true
- * for this. (And must be true on both clients and servers.)
- */
- switch(status) {
- case SUCCESS:
- break;
- case RPC_TIMEOUT:
- case RPC_SERVICE_DISABLED:
- case FS_STALE_HANDLE:
- status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
- if (status == SUCCESS) {
- retry = TRUE;
- break;
- } else {
- return(status);
- }
- default:
- break;
- }
- } while (retry && recov_Transparent);
-
- if (Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID)) {
- Fsio_StreamDestroy(streamPtr);
- } else {
- Fsutil_HandleRelease(streamPtr, TRUE);
- }
- return(status);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_CheckSetID --
- *
- * Determine if the given stream has the set uid or set gid bits set.
- *
- * Results:
- * None.
- *
- * Side effects:
- * *uidPtr and *gidPtr set to -1 if the respective bit isn't set and set
- * to the uid and/or gid of the file otherwise.
- *
- *----------------------------------------------------------------------
- */
- void
- Fs_CheckSetID(streamPtr, uidPtr, gidPtr)
- Fs_Stream *streamPtr;
- int *uidPtr;
- int *gidPtr;
- {
- register Fscache_Attributes *cachedAttrPtr;
-
- switch (streamPtr->ioHandlePtr->fileID.type) {
- case FSIO_LCL_FILE_STREAM:
- cachedAttrPtr =
- &((Fsio_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
- break;
- case FSIO_RMT_FILE_STREAM:
- cachedAttrPtr =
- &((Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
- break;
- case FSIO_LCL_PFS_STREAM:
- case FSIO_RMT_PFS_STREAM:
- /* Could do get attributes request to the PFS here
- * but in general it could be a security hole so
- * we won't allow setuid or setgid programs in a PFS. JMS.
- */
- cachedAttrPtr = (Fscache_Attributes *)NIL;
- break;
- default:
- panic( "Fs_CheckSetID, wrong stream type\n",
- streamPtr->ioHandlePtr->fileID.type);
- return;
- }
- if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
- (cachedAttrPtr->permissions & FS_SET_UID)) {
- *uidPtr = cachedAttrPtr->uid;
- } else {
- *uidPtr = -1;
- }
- if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
- (cachedAttrPtr->permissions & FS_SET_GID)) {
- *gidPtr = cachedAttrPtr->gid;
- } else {
- *gidPtr = -1;
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_FileWriteBackStub --
- *
- * This is the stub for the Fs_WriteBackID system call.
- * The byte arguments are rounded to blocks, and the range of
- * blocks that covers the byte range is written back out of the cache.
- *
- * Results:
- * A return status or SUCCESS if successful.
- *
- * Side effects:
- * Write out the range of blocks in the cache.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fs_FileWriteBackStub(streamID, firstByte, lastByte, shouldBlock)
- int streamID; /* Stream ID of file to write back. */
- int firstByte; /* First byte to write back. */
- int lastByte; /* Last byte to write back. */
- Boolean shouldBlock; /* TRUE if should wait for the blocks to go
- * to disk. */
- {
- Ioc_WriteBackArgs args;
-
- args.firstByte = firstByte;
- args.lastByte = lastByte;
- args.shouldBlock = shouldBlock;
-
- return( Fs_IOControlStub(streamID, IOC_WRITE_BACK, sizeof(args),
- (Address)&args, 0, (Address)0) );
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fs_FileBeingMapped --
- *
- * This is called by VM when a file is being mapped into
- * a user's virtual address (yuck, blech), or is being
- * unmapped from the address space. This does a
- * write-back/invalidate so that the file is not cached
- * by FS any longer. This ensures that paging traffic
- * wont get stale data.
- *
- * Results:
- * A return status or SUCCESS if successful.
- *
- * Side effects:
- * Write out the range of blocks in the cache.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Fs_FileBeingMapped(streamPtr, isMapped)
- Fs_Stream *streamPtr; /* Open stream being mapped in */
- int isMapped; /* 1 if file is being mapped. */
- {
- ReturnStatus status = SUCCESS;
- #if 0
- Fscache_FileInfo *cacheInfoPtr;
- #endif
- Fs_IOCParam ioctl;
- Fs_IOReply reply;
-
- if (isMapped) {
- /*
- * THIS IS BOGUS. The whole thing should be done via I/O control
- * so this routine isn't polluted with checks against the stream type.
- */
- switch(streamPtr->ioHandlePtr->fileID.type) {
- case FSIO_LCL_FILE_STREAM: {
- #if 0
- register Fsio_FileIOHandle *localHandlePtr;
- localHandlePtr = (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
- cacheInfoPtr = &localHandlePtr->cacheInfo;
- #endif
- break;
- }
- case FSIO_RMT_FILE_STREAM: {
- #if 0
- register Fsrmt_FileIOHandle *rmtHandlePtr;
- rmtHandlePtr = (Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr;
- cacheInfoPtr = &rmtHandlePtr->cacheInfo;
- #endif
- break;
- }
- default:
- return(FS_WRONG_TYPE);
- }
- /*
- * Make the file look like a swap file so the local cache
- * is bypassed. Also flush back any modified data so
- * page-ins get good stuff.
- */
- streamPtr->flags |= FS_SWAP;
- }
- /*
- * Tell the file server what's going on.
- */
- if (status == SUCCESS) {
- Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
- ioctl.command = IOC_MAP;
- ioctl.inBuffer = (Address)&isMapped;
- ioctl.inBufSize = sizeof(int);
- ioctl.outBuffer = (Address) NIL;
- ioctl.outBufSize = 0;
- ioctl.format = mach_Format;
- ioctl.procID = procPtr->processID;
- ioctl.familyID = procPtr->familyID;
- ioctl.uid = procPtr->effectiveUserID;
- ioctl.flags = 0;
- status = Fs_IOControl(streamPtr, &ioctl, &reply);
- }
- return(status);
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * Fs_GetFileHandle --
- *
- * Return an opaque handle for a file, really a pointer to its I/O handle.
- * This is used for a subsequent call to Fs_GetSegPtr.
- *
- * Results:
- * A pointer to the I/O handle of the file.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- *
- */
-
- ClientData
- Fs_GetFileHandle(streamPtr)
- Fs_Stream *streamPtr;
- {
- return((ClientData)streamPtr->ioHandlePtr);
- }
-
- /*
- *----------------------------------------------------------------------------
- *
- * Fs_GetSegPtr --
- *
- * Return a pointer to a pointer to the segment associated with this
- * file.
- *
- * Results:
- * A pointer to the segment associated with this file.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- *
- */
-
- Vm_Segment **
- Fs_GetSegPtr(fileHandle)
- ClientData fileHandle;
- {
- Fs_HandleHeader *hdrPtr = (Fs_HandleHeader *)fileHandle;
- Vm_Segment **segPtrPtr;
-
- assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
- switch (hdrPtr->fileID.type) {
- case FSIO_LCL_FILE_STREAM:
- segPtrPtr = &(((Fsio_FileIOHandle *)hdrPtr)->segPtr);
- break;
- case FSIO_RMT_FILE_STREAM:
- segPtrPtr = &(((Fsrmt_FileIOHandle *)hdrPtr)->segPtr);
- break;
- case FSIO_LCL_PFS_STREAM:
- case FSIO_RMT_PFS_STREAM:
- segPtrPtr = &(((Fspdev_ClientIOHandle *)hdrPtr)->segPtr);
- break;
- default:
- segPtrPtr = (Vm_Segment **) NIL;
- panic( "Fs_RetSegPtr, bad stream type %d\n",
- hdrPtr->fileID.type);
- }
- fs_Stats.handle.segmentFetches++;
- if (*segPtrPtr != (Vm_Segment *) NIL) {
- fs_Stats.handle.segmentHits++;
- }
- return(segPtrPtr);
- }
-
-